#ifndef _NE_AABB_H_
#define _NE_AABB_H_

#include <mathematics/Vector3.h>

namespace ne
{
    /*
            1-----2
            /|    /|
            / |   / |
            5-----4  |
            |  0--|--3
            | /   | /
            |/    |/
            6-----7
    */
    enum CornerType
    {
        FAR_LEFT_BOTTOM = 0,
        FAR_LEFT_TOP = 1,
        FAR_RIGHT_TOP = 2,
        FAR_RIGHT_BOTTOM = 3,
        NEAR_RIGHT_TOP = 4,
        NEAR_LEFT_TOP = 5,
        NEAR_LEFT_BOTTOM = 6,
        NEAR_RIGHT_BOTTOM = 7
    };

    enum AABBExtent
    {
        AABB_EXTENT_NULL = 0,
        AABB_EXTENT_FINITE = 1,
        AABB_EXTENT_INFINITE = 2
    };

    class Plane;
    class Sphere;

    class NEAPI AABB
    {
        public:
            AABB();

            AABB(const AABB &a);

            AABB(const Vector3 &minPoint, const Vector3 &maxPoint);

            void redefine(const Vector3 &minPoint, const Vector3 &maxPoint);

            void setExtent(const AABBExtent e);

            AABBExtent getExtent() const;

            bool isNull() const;

            bool isFinite() const;

            bool isInfinite() const;

            Vector3 getCenter() const;

            Vector3 getSize() const;

            Vector3 getHalfSize() const;

            const Vector3* getCorners() const;

            AABB& operator = (const AABB &a);

            bool operator == (const AABB &a) const;

            bool operator != (const AABB &a) const;

            void merge(const AABB &a);

            void merge(const Vector3 &v);

            AABB intersection(const AABB &a) const;

            bool intersects(const AABB &a) const;

            bool intersects(const Sphere &s) const;

            bool intersects(const Plane &p) const;

            bool intersects(const Vector3 &v) const;

            // Function for writing to a stream.
            NEAPI friend std::ostream& operator << (std::ostream &o, const AABB &a);

            ~AABB();

        public:
            Vector3 minimum;
            Vector3 maximum;

        private:
            AABBExtent mExtent;
            mutable Vector3 *mpCorners;
    };
}

#endif
